package com.cmw.socket.l7.server;

import ch.qos.logback.core.util.COWArrayList;
import com.cmw.socket.handler.ClientHandler;
import com.cmw.socket.utils.CloseUtils;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * TCP Server 服务器
 * @author chengmingwei
 * @date 2020-06-26 18:57
 */
@Slf4j
public class TCPServer implements ClientHandler.ClientHandlerCallback {

    private final int port;

    private ClientListener listener;

    private List<ClientHandler> clientHandlerList = new ArrayList<>();

    private final ExecutorService forwardingThreadPoolExecutor;

    private Selector selector;

    private ServerSocketChannel server;

    public TCPServer(int port) {
        this.port = port;
        //转发线程池
        this.forwardingThreadPoolExecutor = Executors.newSingleThreadExecutor();
    }


    public boolean start(){
        try {
            selector = Selector.open();
            ServerSocketChannel server = ServerSocketChannel.open();
            //设置为非阻塞
            server.configureBlocking(false);
            //绑定本地端口
            server.socket().bind(new InetSocketAddress(port));
            //注册客户端连接到过监听
            server.register(selector, SelectionKey.OP_ACCEPT);
            this.server = server;
            log.info("服务器信息：ip -> {}, 端口号 -> {}", server.getLocalAddress().toString(), port);
            //启动客户端监听
            ClientListener listener = this.listener = new ClientListener();
            listener.start();
            log.info("TCPServer 启动成功，ip -> {}, 端口号 -> {}", server.getLocalAddress().toString(), port);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public void stop(){
        if(null != listener){
            listener.exit();
        }
        CloseUtils.close(server, selector);

        synchronized (TCPServer.this){
            clientHandlerList.forEach(cliendHandler -> cliendHandler.exit());
            clientHandlerList.clear();
        }

        //停止线程池
        forwardingThreadPoolExecutor.shutdownNow();
    }

    public synchronized void broadcast(String str){
        clientHandlerList.forEach(clientHandler -> clientHandler.send(str));
    }


    @Override
    public void onSelfClosed(ClientHandler handler) {
        clientHandlerList.remove(handler);
    }

    @Override
    public void onNewMessageArrived(ClientHandler handler, String msg) {
        //异步提交转发任务
        forwardingThreadPoolExecutor.execute(()-> {
            synchronized (TCPServer.this){
                clientHandlerList.forEach(clientHandler -> {
                    if(clientHandler.equals(handler)){
                        //跳过自己
                        return;
                    }
                    // 对其他客户端发送信息
                    clientHandler.send(msg);
                });
            }
        });
    }

    private class ClientListener extends Thread{
        private boolean done = false;


        @Override
        public void run() {
            super.run();
            Selector selector =TCPServer.this.selector;
            log.info("服务器准备就绪~");
            //等待客户端连接
            do{
                try {
                    if(selector.select() == 0){
                        if(done) break;
                        continue;
                    }
                    Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                    while (iterator.hasNext()){
                        if(done){
                            break;
                        }
                        SelectionKey key = iterator.next();
                        iterator.remove();
                        //检查当前Key的状态是否是我们关注的
                        //客户端到过状态
                        if(key.isAcceptable()){
                            ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                            //非阻塞状态拿到客户端连接
                            SocketChannel socketChannel = serverSocketChannel.accept();
                            //客户端构建异步线程
                            ClientHandler clientHandler = new ClientHandler(socketChannel, TCPServer.this);
                            //添加同步处理
                            synchronized (TCPServer.this){
                                clientHandlerList.add(clientHandler);
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    log.error("客户端连接异常:{}", e.getMessage());
                }
            }while (!done);
            log.info("服务器已关闭...");
        }

        void exit(){
            done = true;
            //唤醒当前的阻塞
            selector.wakeup();
        }
    }
}
